﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using GraphEntities;
using NumericalData.DifferentialEquations.Data;
using NumericalData.DifferentialEquations.Methods;
using NumericalData.DifferentialEquations.Methods.Felberg.Constants;

namespace NumericalData.DifferentialEquations.Methods
{
    abstract public class FelbergMethod<T> : SolvationMethod<CauchyProblemContainer> where T:FelbergConstants ,new()
{
        protected T _constants = new T();

        public int Order { get; protected set; }

        public FelbergMethod(CauchyProblemContainer container ):
            base(container)
        {}

        public ODEAnswer Solve(double h)
        {
            var intervalPartition =
                NumericalFunctions.FunctionValues.SplitIntervalWithPresicion(_container.TimeIntervalStart,
                                                                             _container.TimeIntervalStop, h);
            ODEAnswer answer = new ODEAnswer();

            var T = intervalPartition[0];
            var Y = _container.StartValues;
            answer.OdeValues.Add(new ODEValue(T,Y));

            for(var i = 1; i< intervalPartition.Length;++i)
            {
                Console.WriteLine(i);//------------------------------------
                T = intervalPartition[i];
                Y = CalculateNext(T, Y, h);
                answer.OdeValues.Add(new ODEValue(T,Y));
            }

            return answer;
        }

        /// <summary>
        /// Yn+1 = Yn + Summ(from i = 1 to 13)(Pmi*Ki)
        /// where m - method order
        /// </summary>
        /// <param name="tn"></param>
        /// <param name="yn"></param>
        /// <param name="h"></param>
        /// <returns></returns>
        protected Vector CalculateNext(double tn, Vector yn, double h)
        {
            var acc = yn;
            for(var i = 1; i <= 13 ; ++i)
            {
                acc += _constants.GetParameter(i).Value*K(h, tn, yn, i);
            }
            return acc;
        }

        /// <summary>
        /// Ki = h*F(tn + alpha(i)*h, Yn + Summ(from j = 1 to i -1)(betta(i,j)*Kj))
        /// </summary>
        /// <param name="h">step length</param>
        /// <param name="tn"></param>
        /// <param name="yn"></param>
        /// <param name="i"></param>
        /// <returns>yn+1</returns>
        public Vector K(double h,double tn, Vector yn,int i)
        {
            var firstArg = tn + _constants.GetAlpha(i).Value*h;
            var secondArg = yn;
            for (int j = 1; j <= i-1; j++)
            {
                secondArg += _constants.GetBetta(i, j).Value*K(h, tn, yn, j);
            }
            return h*_container.RightPartsVectorFunction(firstArg, secondArg);
        }
    }

    public class SevenOrderFelbergMethod: FelbergMethod<SevenOrderConstants>
    {
        public SevenOrderFelbergMethod(CauchyProblemContainer container) :
            base(container)
        {
            Order = 7;

        }

    }
}
